Skip to content

分享流行的前端产品

技术|源码|设计|参考

公众号二维码

扫码关注艾小逗公众号

第一时间传递给你

首页/javascript/本文内容

js toFixed()四舍五入丢失精度问题处理

错误展示 在这里插入图片描述

看了下lodash的代码,大概是通过使用科学计数法扩大10的n次,将操作数化为整数运算,可以避免精度丢失。

js
 /**
     * Creates a function like `_.round`.
     *
     * @private
     * @param {string} methodName The name of the `Math` method to use when rounding.
     * @returns {Function} Returns the new round function.
     */
    function createRound(methodName) {
      var func = Math[methodName];
      return function(number, precision) {
        number = toNumber(number);
        precision = toInteger(precision);
        if (precision) {
          // Shift with exponential notation to avoid floating-point issues.
          // See [MDN](https://mdn.io/round#Examples) for more details.
          var pair = (toString(number) + 'e').split('e'),
              value = func(pair[0] + 'e' + (+pair[1] + precision));

          pair = (toString(value) + 'e').split('e');
          return +(pair[0] + 'e' + (+pair[1] - precision));
        }
        return func(number);
      };
    }
	var round = createRound('round');

执行结果: 在这里插入图片描述

另外一种方法-来自文心一言,稍作改动

ts
/**
 * 四舍五入
 * @param num
 * @param precision  保留位数
 * @param isReturnNumber 默认返回数字类型,否则返回字符串类型
 * @returns {Number}
 */
export function numberToFixed(num: number, precision = 2, isReturnNumber = true) {
  if (isNaN(num)) return '';
  if (precision < 0 || precision > 20) {
    throw new RangeError('precision must be between 0 and 20');
  }

  const factor = Math.pow(10, precision);
  const value = Math.round(num * factor) / factor;

  // 转换为字符串并填充零(如果需要)
  const stringValue = value.toString();
  const dotIndex = stringValue.indexOf('.');
  let integerPart = '';
  let decimalPart = '';
  if (dotIndex < 0) {
    // 没有小数部分
    integerPart = stringValue;
    decimalPart = '';
  } else {
    integerPart = stringValue.substring(0, dotIndex);
    decimalPart = stringValue.substring(dotIndex + 1);
  }
  if (decimalPart.length < precision) {
    // 小数部分不足,需要补零
    const result = integerPart + '.' + decimalPart.padEnd(precision, '0');
    return isReturnNumber ? Number(result) : result;
  }
  // 小数部分足够,直接返回
  return isReturnNumber ? Number(stringValue) : stringValue;
}